package com.xnyzc.lhy.mis.service.impl.cms.approval;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xnyzc.lhy.common.component.convert.DateToStringConverter;
import com.xnyzc.lhy.common.exception.PangException;
import com.xnyzc.lhy.common.penum.EErrorCode;
import com.xnyzc.lhy.common.penum.EOrderType;
import com.xnyzc.lhy.common.penum.approval.EApplyAmountType;
import com.xnyzc.lhy.common.penum.approval.EApprovalOrderStatus;
import com.xnyzc.lhy.common.penum.dept.EOffIceType;
import com.xnyzc.lhy.common.penum.pay.ETransactionOrderNoType;
import com.xnyzc.lhy.common.penum.push.EJPushConfigKey;
import com.xnyzc.lhy.common.penum.push.EPushCode;
import com.xnyzc.lhy.common.penum.wallet.EIsTransaction;
import com.xnyzc.lhy.common.penum.wallet.ERecordType;
import com.xnyzc.lhy.common.util.CheckUtil;
import com.xnyzc.lhy.common.util.IDUtil;
import com.xnyzc.lhy.common.util.TokenUtil;
import com.xnyzc.lhy.mis.entity.util.OrderUtil;
import com.xnyzc.lhy.mis.feign.FeignMessageSendService;
import com.xnyzc.lhy.mis.mapper.approval.OaCRaiseApplyMapper;
import com.xnyzc.lhy.mis.mapper.cms.amount.OaSysOfficeAmountMapper;
import com.xnyzc.lhy.mis.mapper.cms.amount.OaSysOfficeRecordMapper;
import com.xnyzc.lhy.mis.mapper.sidebar.OaCUserOfficeMapper;
import com.xnyzc.lhy.mis.mapper.sidebar.OaSysOfficeMapper;
import com.xnyzc.lhy.mis.mapper.system.OaSysUserMapper;
import com.xnyzc.lhy.mis.mapper.user.OaCUserMapper;
import com.xnyzc.lhy.mis.mapper.user.wallet.OaCWalletMapper;
import com.xnyzc.lhy.mis.mapper.user.wallet.OaCWalletRecordMapper;
import com.xnyzc.lhy.mis.service.cms.approval.ICmsRaiseApplyService;
import com.xnyzc.lhy.mis.service.cms.util.IOaSysGetOfficeIdListService;
import com.xnyzc.lhy.mis.entity.approval.OaCRaiseApply;
import com.xnyzc.lhy.mis.entity.cms.amount.OaSysOfficeAmount;
import com.xnyzc.lhy.mis.entity.cms.amount.OaSysOfficeRecord;
import com.xnyzc.lhy.mis.entity.sidebar.OaCUserOffice;
import com.xnyzc.lhy.mis.entity.sidebar.OaSysOffice;
import com.xnyzc.lhy.mis.entity.system.OaSysUser;
import com.xnyzc.lhy.mis.entity.user.OaCUser;
import com.xnyzc.lhy.mis.entity.user.wallet.OaCWallet;
import com.xnyzc.lhy.mis.entity.user.wallet.OaCWalletRecord;
import com.xnyzc.lhy.resource.entity.jpush.BizResult;
import com.xnyzc.lhy.resource.entity.jpush.PushInfoEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description 额度审批
 * @Author zhuyubin
 * @Date 2019-08-27 14:58
 **/
@Slf4j
@Service
public class CmsRaiseApplyServiceImpl implements ICmsRaiseApplyService {

    @Autowired
    private IOaSysGetOfficeIdListService iOaSysGetOfficeIdListService;
    @Autowired
    private OaCUserOfficeMapper oaCUserOfficeMapper;
    @Autowired
    private OaCUserMapper oaCUserMapper;
    @Autowired
    private OaCRaiseApplyMapper oaCRaiseApplyMapper;
    @Autowired
    private OaSysOfficeMapper oaSysOfficeMapper;
    @Autowired
    private OaCWalletMapper oaCWalletMapper;
    @Autowired
    private OaCWalletRecordMapper oaCWalletRecordMapper;
    @Autowired
    private OaSysOfficeAmountMapper oaSysOfficeAmountMapper;
    @Autowired
    private OaSysOfficeRecordMapper oaSysOfficeRecordMapper;
    @Autowired
    private OaSysUserMapper oaSysUserMapper;
    @Autowired
    private FeignMessageSendService feignMessageSendService;

    /**
     * 申请提额列表
     * @param sysUserId 后台用户id
     * @param type 权限等级
     * @param tag 租户
     * @param name 用户名
     * @param phone 用户手机号
     * @param officeId 机构名
     * @return
     */
    @Override
    public IPage<Map<String, Object>> selectApplyAmountPage(Long sysUserId, List<String> type, String tag, Long current, String name, String phone, String officeId){
        // 可查看部门id
        List<Long> officeIds = iOaSysGetOfficeIdListService.selectOfficeIdList(sysUserId);
        // 可查看用户
        List<Long> userIds = iOaSysGetOfficeIdListService.selectCUserIdList(sysUserId, type);
        // 模糊查询
        LambdaQueryWrapper<OaCUser> oaCUserLambdaQW = Wrappers.<OaCUser>lambdaQuery().eq(OaCUser::getTag, tag).in(OaCUser::getUserId, userIds);
        if (CheckUtil.objIsNotEmpty(phone)){
            oaCUserLambdaQW.like(OaCUser::getUserPhone, phone);
        }
        if (CheckUtil.objIsNotEmpty(name)){
            oaCUserLambdaQW.like(OaCUser::getUserName, name);
        }
        // 模糊查询userIds
        List<OaCUser> users = oaCUserMapper.selectList(oaCUserLambdaQW);
        userIds = new ArrayList<>();
        for (OaCUser user : users) {
            userIds.add(user.getUserId());
        }
        if(CheckUtil.objIsEmpty(userIds)){
            userIds.add(-1L);
        }
        if (CheckUtil.objIsNotEmpty(officeId)){
            LambdaQueryWrapper<OaCUserOffice> oaCUserOfficeLQW = Wrappers.<OaCUserOffice>lambdaQuery()
                    .eq(OaCUserOffice::getTag, tag)
                    .in(OaCUserOffice::getUserId, userIds);
            List<OaSysOffice> offices = oaSysOfficeMapper.selectList(
                    Wrappers.<OaSysOffice>lambdaQuery()
                            .eq(OaSysOffice::getTag, tag)
                            .eq(OaSysOffice::getParentId, officeId)
                            .in(OaSysOffice::getOfficeId, officeIds));
            // 公司
            if (offices.size() > 0){
                List<Long> deptIds = new ArrayList<>();
                for (OaSysOffice office : offices) {
                    if (EOffIceType.dept.getValue().equals(office.getType())){
                        deptIds.add(office.getOfficeId());
                    }
                }
                if (CheckUtil.objIsEmpty(deptIds)){
                    deptIds.add(-1L);
                }
                oaCUserOfficeLQW.in(OaCUserOffice::getOfficeId, deptIds);
            }
            // 部门
            else {
                oaCUserOfficeLQW.eq(OaCUserOffice::getOfficeId, officeId);
            }
            List<OaCUserOffice> oaCUserOffices = oaCUserOfficeMapper.selectList(oaCUserOfficeLQW);
            userIds = new ArrayList<>();
            for (OaCUserOffice oaCUserOffice : oaCUserOffices) {
                userIds.add(oaCUserOffice.getUserId());
            }
            if (CheckUtil.objIsEmpty(userIds)){
                userIds.add(-1L);
            }
        }
        IPage<OaCRaiseApply> oaCRaiseApplyIPage = new Page<>();
        oaCRaiseApplyIPage.setCurrent(current);
        oaCRaiseApplyIPage.setSize(20L);
        oaCRaiseApplyIPage = oaCRaiseApplyMapper.selectPage(oaCRaiseApplyIPage,
                Wrappers.<OaCRaiseApply>lambdaQuery()
                        .eq(OaCRaiseApply::getTag, tag)
                        .in(OaCRaiseApply::getUserId, userIds)
                        .orderByDesc(OaCRaiseApply::getCreateTime));
        List<Map<String, Object>> list = new ArrayList<>();
        for (OaCRaiseApply oaCRaiseApply : oaCRaiseApplyIPage.getRecords()) {
            userIds.add(oaCRaiseApply.getUserId());
            Map<String, Object> map = new HashMap<>(16);
            map.put("raiseId", oaCRaiseApply.getRaiseId());
            map.put("userId", oaCRaiseApply.getUserId());
            map.put("officeId", "");
            map.put("name", "");
            map.put("phone", "");
            map.put("officeName", "");
            map.put("parentId", "");
            map.put("parentName", "");
            map.put("applyAmount", oaCRaiseApply.getApplyAmount());
            map.put("applyAmountType", EApplyAmountType.findById(oaCRaiseApply.getApplyAmountType()).getDesc());
            map.put("applyReason", oaCRaiseApply.getApplyReason());
            map.put("approvalOpinion", oaCRaiseApply.getApprovalOpinion());
            map.put("approvalStatus", EApprovalOrderStatus.findById(oaCRaiseApply.getApprovalStatus()).getDesc());
            map.put("updateTime", new DateToStringConverter().convert(oaCRaiseApply.getUpdateTime()));
            list.add(map);
        }
        // 可查看部门
        List<OaSysOffice> offices = oaSysOfficeMapper.selectList(Wrappers.<OaSysOffice>lambdaQuery().eq(OaSysOffice::getTag, tag).in(OaSysOffice::getOfficeId, officeIds));
        List<OaCUserOffice> oaCUserOfficeList = oaCUserOfficeMapper.selectList(Wrappers.<OaCUserOffice>lambdaQuery().eq(OaCUserOffice::getTag, tag).in(OaCUserOffice::getOfficeId, officeIds));
        List<OaCUser> oaCUsers = oaCUserMapper.selectList(Wrappers.<OaCUser>lambdaQuery().eq(OaCUser::getTag, tag).in(OaCUser::getUserId, userIds));
        List<Map<String, Object>> result = new ArrayList<>();
        for (Map<String, Object> map : list) {
            for (OaCUserOffice oaCUserOffice : oaCUserOfficeList) {
                Long userId = oaCUserOffice.getUserId();
                if (CheckUtil.objIsEmpty(map.get("userId"), userId)){
                    continue;
                }
                if (userId.equals(Long.valueOf(map.get("userId").toString()))){
                    map.put("officeId", oaCUserOffice.getOfficeId());
                }
            }
            // 部门信息
            for (OaSysOffice office : offices) {
                if (CheckUtil.objIsEmpty(map.get("officeId"))){
                    continue;
                }
                if (office.getOfficeId().equals(Long.valueOf(map.get("officeId").toString()))){
                    map.put("parentId", office.getParentId());
                    map.put("officeName", office.getName());
                }
            }
            // 基本信息
            for (OaCUser oaCUser : oaCUsers) {
                String userId = map.get("userId").toString();
                if (oaCUser.getUserId().equals(Long.valueOf(userId))){
                    map.put("name", oaCUser.getUserName());
                    map.put("phone", oaCUser.getUserPhone());
                }
            }
            // 公司
            for (OaSysOffice office : offices) {
                Object parentId = map.get("parentId");
                if (CheckUtil.objIsEmpty(parentId)){
                    continue;
                }
                if (office.getOfficeId().equals(Long.valueOf(parentId.toString()))){
                    map.put("parentName", office.getName());
                }
            }
            result.add(map);
        }
        IPage<Map<String, Object>> page = new Page<>();
        page.setPages(oaCRaiseApplyIPage.getPages());
        page.setRecords(result);
        page.setTotal(oaCRaiseApplyIPage.getTotal());
        page.setSize(oaCRaiseApplyIPage.getSize());
        page.setCurrent(oaCRaiseApplyIPage.getCurrent());
        return page;
    }

    /**
     * 通过审批
     * @param sysUserId 当前用户
     * @param tag 租户
     * @param raiseId 审批id
     * @return
     */
    @Override
    public String passApplyAmount(Long sysUserId, String tag, String raiseId){
        Date date = new Date();
        OaCRaiseApply oaCRaiseApply = oaCRaiseApplyMapper.selectById(raiseId);
        // 申请额度
        BigDecimal applyAmount = oaCRaiseApply.getApplyAmount();
        // 申请额度类型
        Integer applyAmountType = oaCRaiseApply.getApplyAmountType();
        // 申请人id
        Long userId = oaCRaiseApply.getUserId();
        OaCUserOffice oaCUserOffice = oaCUserOfficeMapper.selectOne(Wrappers.<OaCUserOffice>lambdaQuery().eq(OaCUserOffice::getTag, tag).eq(OaCUserOffice::getUserId, userId));
        if (CheckUtil.objIsEmpty(oaCUserOffice)){
            throw PangException.create(EErrorCode.unOffice);
        }
        // 部门id
        Long officeId = oaCUserOffice.getOfficeId();
        OaSysOfficeAmount oaSysOfficeAmount = oaSysOfficeAmountMapper.selectOne(Wrappers.<OaSysOfficeAmount>lambdaQuery().eq(OaSysOfficeAmount::getTag, tag).eq(OaSysOfficeAmount::getOfficeId, officeId));
        if (CheckUtil.objIsEmpty(oaSysOfficeAmount)){
            throw PangException.create(EErrorCode.undistributionAmount);
        }
        BigDecimal officeAmount;
        // 个人
        if (EApplyAmountType.personalOfficial.getValue().equals(applyAmountType)){
            officeAmount = oaSysOfficeAmount.getPersonalAmount();

        }
        // 部门
        else {
            officeAmount = oaSysOfficeAmount.getOfficeAmount();
        }
        // 剩余部门额度
        BigDecimal lastAmount = officeAmount.subtract(applyAmount);
        BigDecimal zero = new BigDecimal("0");
        // 部门额度够不够
        if (lastAmount.compareTo(zero) != -1){
            oaSysOfficeAmount.setUpdateUser(sysUserId);
            oaSysOfficeAmount.setUpdateTime(date);
            // 个人
            if (EApplyAmountType.personalOfficial.getValue().equals(applyAmountType)){
                oaSysOfficeAmount.setPersonalAmount(lastAmount);
            }
            // 部门
            else {
                oaSysOfficeAmount.setOfficeAmount(lastAmount);
            }
            int i = oaSysOfficeAmountMapper.updateById(oaSysOfficeAmount);
            if (i != 1){
                throw PangException.create(EErrorCode.applyAmountOperateFailure);
            }
            // 插入额度分配记录
            this.insertOfficeRecord(officeId, userId, applyAmount, applyAmountType, sysUserId, tag, date);
        } else {
            throw PangException.create(EErrorCode.officeAmountLack);
        }
        // 通过审批
        oaCRaiseApply.setUpdateUser(sysUserId);
        oaCRaiseApply.setUpdateTime(date);
        oaCRaiseApply.setApprovalStatus(EApprovalOrderStatus.pass.getValue());
        int i = oaCRaiseApplyMapper.updateById(oaCRaiseApply);
        if (i != 1){
            throw PangException.create(EErrorCode.applyAmountOperateFailure);
        }
        // 更新钱包
        OaCWallet oaCWallet = this.updateOaCWallet(userId, tag, date, sysUserId, applyAmountType, applyAmount);
        // 插入用户钱包记录
        this.insertWalletRecord(userId, applyAmountType, applyAmount, date, sysUserId, tag, oaCWallet);
        // 极光推送
        this.OajPush(userId, tag);
        return EErrorCode.applyAmountPass.getDesc();
    }

    /**
     * 驳回审批
     * @param sysUserId 当前用户
     * @param raiseId 审批id
     * @return
     */
    @Override
    public String rejectApplyAmount(Long sysUserId, String raiseId, String approvalOpinion){
        OaCRaiseApply oaCRaiseApply = oaCRaiseApplyMapper.selectById(raiseId);
        if (CheckUtil.objIsEmpty(oaCRaiseApply)){
            throw PangException.create(EErrorCode.applyAmountOperateFailure);
        }
        oaCRaiseApply.setUpdateTime(new Date());
        oaCRaiseApply.setUpdateUser(sysUserId);
        oaCRaiseApply.setApprovalStatus(EApprovalOrderStatus.reject.getValue());
        oaCRaiseApply.setApprovalOpinion(approvalOpinion);
        int i = oaCRaiseApplyMapper.updateById(oaCRaiseApply);
        if (i != 1){
            throw PangException.create(EErrorCode.applyAmountOperateFailure);
        }
        return EErrorCode.applyAmountReject.getDesc();
    }

    /**
     * 插入用户记录
     * @param officeId 部门id
     * @param userId 用户id
     * @param applyAmount 额度
     * @param applyAmountType 额度类型
     * @param sysUserId 后台用户
     * @param tag 租户
     * @param date 当前时间
     */
    private void insertOfficeRecord(Long officeId, Long userId, BigDecimal applyAmount, Integer applyAmountType, Long sysUserId, String tag, Date date){
        OaSysOfficeRecord oaSysOfficeRecord = new OaSysOfficeRecord();
        oaSysOfficeRecord.setOfficeRecordId(IDUtil.nextId());
        oaSysOfficeRecord.setOfficeId(officeId);
        oaSysOfficeRecord.setAssignUserid(userId);
        oaSysOfficeRecord.setAmount(applyAmount);
        oaSysOfficeRecord.setAmountType(applyAmountType);
        OaSysUser oaSysUser = oaSysUserMapper.selectById(sysUserId);
        if (CheckUtil.objIsNotEmpty(oaSysUser)){
            oaSysOfficeRecord.setCreateName(oaSysUser.getName());
        }
        oaSysOfficeRecord.setTag(tag);
        oaSysOfficeRecord.setCreateUser(sysUserId);
        oaSysOfficeRecord.setCreateTime(date);
        oaSysOfficeRecord.setUpdateUser(sysUserId);
        oaSysOfficeRecord.setUpdateTime(date);

        int i = oaSysOfficeRecordMapper.insert(oaSysOfficeRecord);
        if (i != 1){
            throw PangException.create(EErrorCode.applyAmountOperateFailure);
        }
    }

    /**
     * 更新用户钱包
     * @param userId 用户id
     * @param tag 租户
     * @param date 当前时间
     * @param sysUserId 后台用户
     * @param applyAmountType 额度类型
     * @param applyAmount 额度
     */
    private OaCWallet updateOaCWallet(Long userId, String tag, Date date, Long sysUserId, Integer applyAmountType, BigDecimal applyAmount){
        OaCWallet oaCWallet = oaCWalletMapper.selectOne(
                Wrappers.<OaCWallet>lambdaQuery()
                        .eq(OaCWallet::getTag, tag)
                        .eq(OaCWallet::getUserId, userId));
        if (CheckUtil.objIsEmpty(oaCWallet)){
            throw PangException.create(EErrorCode.unWallet);
        }
        oaCWallet.setUpdateTime(date);
        oaCWallet.setUpdateUser(sysUserId);
        // 个人额度
        BigDecimal personalOfficialBalance = oaCWallet.getPersonalOfficialBalance();
        // 部门额度
        BigDecimal deptOfficialBalance = oaCWallet.getDeptOfficialBalance();
        // 个人
        if (EApplyAmountType.personalOfficial.getValue().equals(applyAmountType)){
            // 有没额度
            if (CheckUtil.objIsNotEmpty(personalOfficialBalance)){
                oaCWallet.setPersonalOfficialBalance(personalOfficialBalance.add(applyAmount));
            } else {
                oaCWallet.setPersonalOfficialBalance(applyAmount);
            }
        }
        // 部门
        else {
            if (CheckUtil.objIsNotEmpty(deptOfficialBalance)){
                oaCWallet.setDeptOfficialBalance(deptOfficialBalance.add(applyAmount));
            } else {
                oaCWallet.setDeptOfficialBalance(applyAmount);
            }
        }
        int i = oaCWalletMapper.updateById(oaCWallet);
        if (i != 1){
            throw PangException.create(EErrorCode.applyAmountOperateFailure);
        }
        return oaCWallet;
    }

    /**
     * 插入用户钱包记录
     * @param userId 用户id
     * @param applyAmountType 额度类型
     * @param applyAmount 额度
     * @param date 当前时间
     * @param sysUserId 后台用户id
     * @param tag 租户
     * @param oaCWallet 用户钱包实体
     */
    private void insertWalletRecord(Long userId, Integer applyAmountType, BigDecimal applyAmount, Date date, Long sysUserId, String tag, OaCWallet oaCWallet){
        OaCWalletRecord oaCWalletRecord = new OaCWalletRecord();
        oaCWalletRecord.setRecordId(IDUtil.nextId());
        oaCWalletRecord.setUserId(userId);
        // 个人 或 部门
        if (EApplyAmountType.personalOfficial.getValue().equals(applyAmountType)){
            oaCWalletRecord.setOrderNo(OrderUtil.orderNo(EOrderType.TEGR));
            oaCWalletRecord.setRecordType(ERecordType.myTopUp.getType());
            oaCWalletRecord.setTransactionOrderNo(OrderUtil.transactionOrderNo(ETransactionOrderNoType.personalBusiness));
        } else {
            oaCWalletRecord.setOrderNo(OrderUtil.orderNo(EOrderType.TEGW));
            oaCWalletRecord.setRecordType(ERecordType.officialTopUp.getType());
            oaCWalletRecord.setTransactionOrderNo(OrderUtil.transactionOrderNo(ETransactionOrderNoType.deptService));
        }
        oaCWalletRecord.setWalletBalance(oaCWallet.getWalletBalance());
        oaCWalletRecord.setDeptOfficialBalance(oaCWallet.getDeptOfficialBalance());
        oaCWalletRecord.setPersonalOfficialBalance(oaCWallet.getPersonalOfficialBalance());
        oaCWalletRecord.setActualAmount(applyAmount);
        oaCWalletRecord.setIsTransaction(EIsTransaction.paySuccess.getValue());
        oaCWalletRecord.setTransactionTime(date);
        oaCWalletRecord.setTag(tag);
        oaCWalletRecord.setCreateUser(sysUserId);
        oaCWalletRecord.setCreateTime(date);
        oaCWalletRecord.setUpdateUser(sysUserId);
        oaCWalletRecord.setUpdateTime(date);
        int i = oaCWalletRecordMapper.insert(oaCWalletRecord);
        if (i != 1){
            throw PangException.create(EErrorCode.applyAmountOperateFailure);
        }
    }

    /**
     * 极光推送 申请提额通过
     * @param userId
     */
    private void OajPush(Long userId, String tag){
        OaCUser oaCUser = oaCUserMapper.selectById(userId);
        if (CheckUtil.objIsNotEmpty(oaCUser)){
            // 手机号们
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("expand", "");
            List<String> phones = new ArrayList<>();
            phones.add(oaCUser.getUserPhone());
            PushInfoEntity pushInfoEntity = new PushInfoEntity();
            pushInfoEntity.setPhones(phones);
            pushInfoEntity.setPushCode(EPushCode.improveAmount.getValue());
            pushInfoEntity.setExtras(jsonObject);
            pushInfoEntity.setClientId(EJPushConfigKey.passenger.getValue());
            pushInfoEntity.setTag(tag);
            BizResult bizResult = feignMessageSendService.pushMessage(pushInfoEntity);

            log.info("{}", bizResult.toString());

            if (bizResult.getCode() == 1) {
                log.info("推送成功");
            } else {
                log.info("推送失败");
            }
        }
    }
}
